home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-08-04 | 18.7 KB | 691 lines | [TEXT/KAHL] |
- /******************************************************************************
- CBrowseResDoc.c
-
-
- SUPERCLASS = CDocument
-
- Copyright © 1991 Symantec Corporation. All rights reserved.
-
- CBrowseResDoc is a document class for browsing resource files. It can
- display the contents of existing resource files, but not modify their
- contents or create new resource files.
- It provides examples of
- - a multi-window document
- - using the Table and Dialog classes
- - using resource files. However, resources are handled in a pretty
- minimalist way. Applications that create, edit, and save resource
- files will need to do more.
-
- When you open a resource file, CBrowseResDoc creates a window with a
- CScrollPane and a CResTypePane. The CResTypePane displays a scrolling
- list of the resource types in the file. Any types that CBrowseResDoc
- can display are shown in bold.
-
- For any resource type, double-clicking opens a new window showing
- a list of all the resources of that type. The window is implemented
- by creating an instance of CResBrowser or an appropriate subclass.
- ResBrowser will display a list of resource types, but cannot open
- individual resources. Subclasses of ResBrowser, such as CDLOGBrowser
- can create windows for viewing individual resources. They may also
- elect to display the list of resources in a custom view by overriding
- CResBrowser::BuildWindow.
-
- The other new subclasses used to implement CBrowseResDoc are:
- CResTypePane, CResListPane, CResBrowser, and CDLOGBrowser.
-
-
- ******************************************************************************/
-
- #include "CBrowseResDoc.h"
- #include <CDesktop.h>
- #include "ResourceStructs.h"
- #include <CScrollPane.h>
- #include <CDecorator.h>
- #include "CResTypePane.h"
- #include <CResFile.h>
- #include "CDLOGBrowser.h"
- #include "CDRVRBrowser.h"
- #include <TCLUtilities.h>
- #include <CArray.h>
- #include <CWindow.h>
-
- #define cmdOpenType 1050 // open window on a resource type
- #define cmdOpenResource 1051 // open window on a resource
- #define kResBrowseWind 1025 // 'WIND' resource ID
-
- extern CDesktop *gDesktop;
- extern CDecorator *gDecorator;
- extern CBartender *gBartender; /* The menu handling object */
-
- /******************************************************************************
- IBrowseResDoc
-
- The initialization method. Any new instance variables defined by this
- class should be initialized. You must always call the superclass's
- initialization method as early as possible, but first null out any
- pointer references in the event that there is a failure during
- initialization.
-
- ******************************************************************************/
-
- void CBrowseResDoc::IBrowseResDoc( CApplication *aSupervisor, Boolean printable)
- {
- itsResTypes = NULL;
- itsTypePane = NULL;
-
- CDocument::IDocument( aSupervisor, printable);
-
- // Create a new, empty array for the resource type information
-
- itsResTypes = new CArray;
-
- // The argument to IArray is the size of each element in this array
-
- itsResTypes->IArray( sizeof( tResTypeInfo));
- }
-
- /******************************************************************************
- NewFile
-
- Does not create new files. Any document that creates new files should
- override NewFile and create and show a new, untitled window.
-
- ******************************************************************************/
-
- void CBrowseResDoc::NewFile(void)
- {
-
- }
-
- /******************************************************************************
- OpenFile
-
- Open the existing file given in macSFReply. This requires creating a
- new File object, opening the file, creating a window, and installing the
- data in the window.
-
- ******************************************************************************/
-
- void CBrowseResDoc::OpenFile( SFReply *macSFReply)
- {
- CResFile *resFile;
- short savedRes;
-
- /*
- * Failure handling:
- * The only objects created within the activation of this
- * method are those already known to the standard TCL classes,
- * e.g. itsFile, itsWindow, subviews of itsWindow, etc. Before
- * calling OpenFile, CDemoApp has posted an exception handler.
- * If an exception occurs, CDemoApp will call Dispose for this
- * document, which in turn will dispose of the file, the window
- * all all its subviews. Therefore, no exception handler is
- * needed for this method.
- */
-
- // We use the TCL class CResFile to represent our resource file.
-
- resFile = new CResFile;
-
- // assign the file to CDocument::itsFile so CDocument knows about the file.
-
- itsFile = resFile;
-
- // call its initialization method
-
- resFile->IResFile();
-
- // fill in the file information
-
- resFile->SFSpecify( macSFReply);
-
- // If the file has no resource fork, we'll just display
- // an empty window. Since we don't modify the file, there's
- // no point in creating a resource fork.
-
- if (resFile->HasResFork())
- {
- // Save the current resource file, because opening
- // a resource file makes it the current file. Since
- // we don't know anything about the resources in this
- // file we don't want to take the chance that it has
- // resources that could conflict with our application
- // or system resources. Therefore we will always save
- // and restore the current resource file when dealing
- // with this file.
-
- savedRes = CurResFile();
-
- // open the file
-
- resFile->Open( fsRdWrPerm);
-
- // restore the old resource file
-
- UseResFile( savedRes);
-
- // Build a list of all types in this file
-
- BuildTypeList();
- }
-
- // create the resource type window
-
- BuildMainWindow();
-
- // Ask gDecorator to place this window. StaggerWindow places the
- // window, but does not change its size.
-
- gDecorator->StaggerWindow( itsWindow);
-
- // Set the window title to the file name
-
- itsWindow->SetTitle( macSFReply->fName);
-
- // Finally, show the window
-
- itsWindow->Select();
- }
-
- /******************************************************************************
- DoCommand
-
- The cmdOpenType command is generated by a double-click in the type list.
- ******************************************************************************/
-
- void CBrowseResDoc::DoCommand( long aCommand)
- {
- switch( aCommand)
- {
- case cmdOpenType:
- OpenTypeWindow();
- break;
-
- // Always call inherited::DoCommand for commands you don't handle
-
- default:
- inherited::DoCommand( aCommand);
- break;
- }
- }
-
- /******************************************************************************
- Dispose
-
- Release all memory used by this object.
- ******************************************************************************/
-
- void CBrowseResDoc::Dispose( void)
- {
- // We only need to dispose of instance variables declared by
- // this subclass that our superclass wouldn't automatically
- // dispose of. Therefore we ignore itsFile, itsWindow, etc,
- // and only dispose of itsResTypes.
-
- ForgetObject( itsResTypes);
- inherited::Dispose();
- }
-
- /******************************************************************************
- CanOpenType
-
- Returns true if we will be able to open a window for a resource
- of the given type.
- ******************************************************************************/
-
- Boolean CBrowseResDoc::CanOpenType( ResType aResType)
- {
- switch(aResType)
- {
- case 'DLOG':
- case 'DRVR':
- return 1;
- }
- return 0;
- }
-
- /******************************************************************************
- BuildMainWindow
-
- Creates the resource type window and all its subviews.
- ******************************************************************************/
-
- void CBrowseResDoc::BuildMainWindow( void)
- {
- CScrollPane *scrollPane;
-
- // Create a window object and initialize it from a WIND resource
-
- itsWindow = new CWindow;
- itsWindow->IWindow( kResBrowseWind, FALSE, gDesktop, this);
-
- // Create scroll pane with a vertical scroll bar and a size box.
-
- scrollPane = new CScrollPane;
- scrollPane->IScrollPane( itsWindow, this, 0, 0, 0, 0,
- sizELASTIC, sizELASTIC, FALSE, TRUE, TRUE);
-
- // Fit the scroll pane to the window
-
- scrollPane->FitToEnclFrame( TRUE, TRUE);
-
- // Create a CResTypePane for displaying the list of resource types
-
- itsTypePane = new CResTypePane;
- itsTypePane->IResTypePane( scrollPane, this, 0, 0, 0, 0,
- sizELASTIC, sizELASTIC);
- itsTypePane->FitToEnclosure( TRUE, TRUE);
-
- // Link itsTypePane to itsResTypes.
-
- itsTypePane->SetArray( itsResTypes, FALSE);
-
- // Double-clicking in itsTypePane will send the cmdOpenType command
- // to this document.
-
- itsTypePane->SetDblClickCmd( cmdOpenType);
-
- // Set the selection behavior for the type list so only one row
- // is selected at a time.
-
- itsTypePane->SetSelectionFlags( selOnlyOne);
-
- // Set itsTypePane as the panorama for the scroll pane.
-
- scrollPane->InstallPanorama( itsTypePane);
-
- // itsGopher is the object that will be the first to receive
- // menu commands, keystrokes, and idle time for this document.
-
- // itsMainPane is the pane that is printed if the document is
- // printable.
-
- itsGopher = itsMainPane = itsTypePane;
-
- }
-
- /******************************************************************************
- BuildTypeList
-
- Build a list of all the resource types in the file
-
- ******************************************************************************/
-
- void CBrowseResDoc::BuildTypeList( void)
- {
- short savedResFile = CurResFile();
- short currIndex, numTypes;
- tResTypeInfo typeInfo;
-
- /*
- * Failure Handling:
- * Its possible for a failure to occur during this method.
- * For example, we could run out of memory while trying
- * to insert into itsResTypes. Rather than exiting
- * this method with the current resource file set to
- * itsFile, and itsResTypes in a partially consistent
- * state, we post an exception handler to cleanup before
- * propagating the exception.
- */
-
- TRY
- {
- // Make itsFile the current resource file
-
- ((CResFile*)itsFile)->MakeCurrent();
-
- // Get the number of types in the resource file.
- // Then for each type, fill in a tResTypInfo struct
- // and insert it into itsResTypes array.
-
- numTypes = Count1Types();
- for( currIndex = 1; currIndex <= numTypes; currIndex++)
- {
- // what is the type?
-
- Get1IndType( &typeInfo.type, currIndex);
-
- if (ResError() != noErr)
- break;
-
- // NULL the window field. It stores a reference
- // to a Director for the window for that type.
-
- typeInfo.window = NULL;
-
- // can we open a window on resources of this type?
-
- typeInfo.editable = CanOpenType( typeInfo.type);
-
- // insert it to the array
-
- itsResTypes->InsertAtIndex( &typeInfo, currIndex);
- }
- // restore the original resource file
-
- UseResFile( savedResFile);
- }
- CATCH
- {
- // Something failed here. Restore the resource, empty the
- // array, then allow the exception to propagate.
-
- UseResFile( savedResFile);
- itsResTypes->Resize( 0);
- }
- ENDTRY;
- }
-
- /******************************************************************************
- OpenTypeWindow
-
- Opens a window for the given resource type. Called in response to
- the cmdOpenType command.
- ******************************************************************************/
-
- void CBrowseResDoc::OpenTypeWindow( void)
- {
- Cell selectedCell;
- tResTypeInfo typeInfo;
-
- // Get the tResTypeInfo struct corresponding to
- // the selected cell. If a window already exists
- // for this type, then bring it to the front, otherwise
- // call MakeTypeBrowser to make a new window.
-
- selectedCell.h = selectedCell.v = 0;
- if (itsTypePane->GetSelect( TRUE, &selectedCell))
- {
- itsResTypes->GetItem( &typeInfo, selectedCell.v + 1);
- if (typeInfo.window)
- {
- // typeInfo.window is a director responsible
- // for displaying the given type. Select its
- // window.
-
- typeInfo.window->GetWindow()->Select();
- }
- else
- {
- // No director exists. Create a new one, then
- // store the reference back into the array so
- // we'll know the window already exists later on.
-
- typeInfo.window = MakeTypeBrowser( typeInfo.type);
- itsResTypes->SetItem( &typeInfo, selectedCell.v + 1);
- }
- }
- }
-
- /******************************************************************************
- MakeTypeBrowser
-
- Create a browser for the given resource type. For the types
- we know about, like DLOG, we create a special subclass of CResBrowser.
- Otherwise we create a CResBrowser, which supplies the default behavior.
-
- ******************************************************************************/
-
- CResBrowser *CBrowseResDoc::MakeTypeBrowser( ResType aType)
- {
- CArray *resList = NULL;
- CResBrowser *director = NULL;
-
- /*
- * Failure Handling:
- * If this method fails, that means we couldn't
- * successfully open the new browser. If
- * resList or director were allocated, then
- * free them before allowing the exception to propagate.
- */
-
- TRY
- {
- resList = BuildResourceList( aType);
-
- switch(aType)
- {
- case 'DLOG':
- {
- CDLOGBrowser *dlgDir = new CDLOGBrowser;
- director = dlgDir;
- dlgDir->IDLOGBrowser( this, resList);
- break;
- }
- case 'DRVR':
- {
- CDRVRBrowser *dlgDir = new CDRVRBrowser;
- director = dlgDir;
- dlgDir->IDRVRBrowser( this, resList);
- break;
- }
- default:
- {
- director = new CResBrowser;
- director->IResBrowser( this, aType, resList);
- break;
- }
- }
- }
- CATCH
- {
- // Both resList and director were initialized to NULL at the
- // start of this method. If either is not NULL now, then
- // we know it was in fact created. If director was
- // created, then its initialization method was called,
- // and ownership of the list was passed of to it. If it wasn't
- // created, then we must dispose of the list.
-
- if (!director)
- ForgetObject( resList);
- ForgetObject( director);
- }
- ENDTRY;
-
- return director;
- }
-
- /******************************************************************************
- BuildResourceList
-
- Build an array of tResourceInfo structs, containing information
- about all the resources in the file of the given type.
-
- ******************************************************************************/
-
- CArray *CBrowseResDoc::BuildResourceList( ResType aType)
- {
- CArray *resList = NULL;
- short savedRes = CurResFile();
- short currIndex, numRes;
- tResourceInfo resInfo;
- ResType type;
- Boolean savedAlloc = kAllocCantFail;
-
- /*
- * Failure Handling:
- * If an exception occurs, we want to dispose of the
- * array, because it was not completely created.
- * Also, we ensure that the resource file is restored.
- */
-
- TRY
- {
- // Create an array whose elements are tResourceInfo
-
- resList = new CArray;
- resList->IArray( sizeof( tResourceInfo));
-
- // None of the resources have a window yet
-
- resInfo.window = NULL;
-
- // make the resource file current
-
- ((CResFile*)itsFile)->MakeCurrent();
-
- // For each resource of the given type, fill in a
- // tResourceInfo struct and insert it to the array
-
- numRes = Count1Resources( aType);
- for( currIndex = 1; currIndex <= numRes; currIndex++)
- {
-
- // Before attempting to load the resource,
- // tell the TCL that this is a non-critical
- // attempt to allocate memory that is allowed
- // to fail.
-
- savedAlloc = SetAllocation( kAllocCanFail);
-
- resInfo.resource = Get1IndResource( aType, currIndex);
-
- savedAlloc = SetAllocation( savedAlloc);
-
- // Raise an exception if we couldn't load the
- // resource.
-
- FailNIL(resInfo.resource);
-
- // Get its size, ID, and name
-
- resInfo.size = GetHandleSize( resInfo.resource);
- GetResInfo( resInfo.resource, &resInfo.ID, &type,
- resInfo.name);
-
- // allow the resource to be purged. We'll explicitly
- // load it if we need it later.
-
- HPurge( resInfo.resource);
-
- // put the info into the array.
-
- resList->InsertAtIndex( &resInfo, currIndex);
- }
- }
- CATCH
- {
- // Something failed. Restore the resource file, free the list
- // and propagate the exception.
-
- UseResFile( savedRes);
- ForgetObject( resList);
- }
- ENDTRY;
-
- // We were successful :-). Restore the original resource
- // file, and return the array.
-
- UseResFile( savedRes);
- return resList;
-
- }
-
- /******************************************************************************
- RemoveDirector {OVERRIDE}
-
- This is called when one of our subdirectors, i.e. one of the
- resource browsers was closed. We override in order to remove
- the reference to the window from the reference to it we
- stored in itsResTypes.
-
- ******************************************************************************/
-
- static int FindTypeDirector( CResBrowser *typeDirector, tResTypeInfo *typeInfo)
- {
- if (typeInfo->window == typeDirector)
- {
- typeInfo->window = NULL;
- return 0;
- }
- return 1;
- }
-
- void CBrowseResDoc::RemoveDirector( CDirector *aDirector)
- {
- // Search the array, looking for the entry corresponding to
- // aDirector. Since the search function clears the entry
- // there is nothing else to do.
-
- if (itsResTypes)
- itsResTypes->Search( aDirector, (CompareFunc) FindTypeDirector);
-
- inherited::RemoveDirector( aDirector);
- }
-
- void CBrowseResDoc::AddType( Handle theHandle, ResType newtype, Str255 newname)
- {
- short savedResFile = CurResFile();
- TRY
- {
- Str255 DRVRname;
- int numRes,currIndex,i = 0;
- int maxid = 1;
- int newid = 0;
- tResTypeInfo typeInfo;
- BlockMove(newname+1, DRVRname+2, *newname);
- *DRVRname = 1+*newname;
- DRVRname[1] = 0;
- // Make itsFile the current resource file
- ((CResFile*)itsFile)->MakeCurrent();
- numRes = Count1Resources( newtype);
- for( currIndex = 1; currIndex <= numRes; currIndex++)
- {
- ResType type;
- tResourceInfo resInfo;
- Boolean savedAlloc = SetAllocation( kAllocCanFail);
- resInfo.resource = Get1IndResource( newtype, currIndex);
- savedAlloc = SetAllocation( savedAlloc);
- FailNIL(resInfo.resource);
- resInfo.size = GetHandleSize( resInfo.resource);
- GetResInfo( resInfo.resource, &resInfo.ID, &type, resInfo.name);
- if (EqualString(DRVRname, resInfo.name, TRUE, TRUE))
- {
- newid = resInfo.ID;
- RmveResource(resInfo.resource);
- AddResource(theHandle,newtype,newid,DRVRname);
- }
- else HPurge( resInfo.resource);
- if (maxid <= resInfo.ID) maxid = resInfo.ID+1;
- }
- if (!newid)
- {
- newid = maxid;
- AddResource(theHandle,newtype,newid,DRVRname);
- }
- FailOSErr (ResError());
- dirty = TRUE;
- UseResFile( savedResFile);
- if (numRes) i = itsResTypes->GetNumItems();
- while ( i )
- {
- itsResTypes->GetItem( &typeInfo, i);
- if (typeInfo.type == newtype) i = 0;
- else i--;
- }
- if ((typeInfo.type != newtype) || !numRes)
- {
- typeInfo.window = NULL;
- typeInfo.type = newtype;
- typeInfo.editable = CanOpenType( typeInfo.type);
- itsResTypes->InsertAtIndex( &typeInfo, 1);
- itsTypePane->SetArray( itsResTypes, FALSE);
- itsWindow->Select();
- }
- else if (typeInfo.window) typeInfo.window->Close(FALSE);
- }
- CATCH
- {
- UseResFile( savedResFile);
- }
- ENDTRY;
- }
-
- Boolean CBrowseResDoc::DoSave(void)
- {
- ((CResFile *)itsFile)->Update();
- dirty = FALSE; /* Document is no longer dirty */
- gBartender->DisableCmd(cmdSave);
- return(TRUE); /* Save was successful */
- }
-